package com.demo.redis;

import org.redisson.api.RFuture;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDateTime;
import java.util.concurrent.TimeUnit;

/**
 * 分布式锁相关
 * */
@RestController
public class SetNxDemo {

    private int papers = 100;

    @Autowired
    private RedisTemplate redisTemplate;

    @RequestMapping("/redis/sell")
    public void redisSell(){
        //也可以设置过期时间
        Boolean redisFlag = redisTemplate.opsForValue().setIfAbsent("redisKey", 1);
        try{
            if(redisFlag){
                if(papers > 0) {
                    System.out.println("减一" + --papers);
                }
            }
        }finally {
            redisTemplate.delete("redisKey");
        }
    }

    @Autowired
    private RedissonClient redisClient;

    @RequestMapping("/redisson/tryLock")
    public void redissonSell(){
        RLock pz = redisClient.getLock("pz");
        try{
            boolean b = pz.tryLock();  //抢不到就返回 false，不设置过期时间，有看门狗
//            boolean b = pz.tryLock(2, TimeUnit.SECONDS);  //抢两秒，抢不到返回 false，不设置过期时间，有看门狗
//            boolean b = pz.tryLock(3, 2, TimeUnit.SECONDS);  //抢三秒，两秒过期时间，无看门狗
            if(b) {
                System.out.println(Thread.currentThread().getName() + "在" + LocalDateTime.now().toString() + "时间抢到锁了！！");
                Thread.sleep(5000);
            }else{
                System.out.println(Thread.currentThread().getName()+ "在" + LocalDateTime.now().toString() + "：获取锁失败！！");
            }
        }catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            //如果是当前线程持有锁
            if(pz.isHeldByCurrentThread()) {
                pz.unlock();
            }
        }
    }

    @RequestMapping("/redisson/lock")
    public void redisson(){
        RLock pz = redisClient.getLock("pz");
        try {
//            pz.lock();      //一直阻塞，直到抢到锁为止
            pz.lock(2, TimeUnit.SECONDS);   //一直阻塞，两秒过期时间
            System.out.println(Thread.currentThread().getName() + "在" + LocalDateTime.now().toString() + "时间抢到锁了！！");
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            System.out.println("-----------");
        } finally {
            //如果是当前线程持有锁
            if(pz.isHeldByCurrentThread()) {
                pz.unlock();
            }
        }
    }

    @RequestMapping("/redisson/lock/async")
    public void redissonAsync(){
        RLock pz = redisClient.getLock("pz");
        try{
            //无论获取锁是否成功，都继续下一步操作。当获取锁成功之后，再执行回调方法
            RFuture<Void> voidRFuture = pz.lockAsync();
            System.out.println(Thread.currentThread().getName() + "在" + LocalDateTime.now().toString() + "不知道加没加到锁！！");
            try {
                Thread.sleep(2_000);
                System.out.println(Thread.currentThread().getName() + "在" + LocalDateTime.now().toString() + "睡眠过了！！");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //回调方法
            voidRFuture.whenCompleteAsync((aVoid, throwable) -> {
                System.out.println(Thread.currentThread().getName() + "在" + LocalDateTime.now().toString() + "执行的操作！！");
                try {
                    Thread.sleep(1_000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }finally {
            pz.unlock();
        }
    }
}
